// src/utils/cache.ts
let EXPIRE = 0;

interface CacheTag {
  key: string;
  expire: number;
}

class Cache {
  private cacheSetHandler: typeof uni.setStorageSync;
  private cacheGetHandler: typeof uni.getStorageSync;
  private cacheClearHandler: typeof uni.removeStorageSync;
  private cacheExpire: string;

  constructor() {
    this.cacheSetHandler = uni.setStorageSync;
    this.cacheGetHandler = uni.getStorageSync;
    this.cacheClearHandler = uni.removeStorageSync;
    this.cacheExpire = "UNI-APP:TAG";
    this.clearOverdue();
  }

  /**
   * 获取当前时间戳
   */
  private time(): number {
    return Math.round(new Date().getTime() / 1000);
  }

  /**
   * 字符串转时间戳
   * @param expiresTime 时间字符串
   */
  private strTotime(expiresTime: string): number {
    let expires_time = expiresTime.substring(0, 19);
    expires_time = expires_time.replace(/-/g, "/");
    return Math.round(new Date(expires_time).getTime() / 1000);
  }

  /**
   * 设置过期时间缓存
   * @param key 缓存键
   * @param expire 过期时间（秒）
   */
  private setExpireCaheTag(key: string, expire?: number): void {
    expire = expire !== undefined ? expire : EXPIRE;
    if (typeof expire === "number") {
      let tag: CacheTag[] | any = this.cacheGetHandler(this.cacheExpire);
      let newTag: CacheTag[] = [];
      let newKeys: string[] = [];

      if (Array.isArray(tag)) {
        newTag = tag.map((item: CacheTag) => {
          newKeys.push(item.key);
          if (item.key === key) {
            item.expire = expire === 0 ? 0 : this.time() + expire;
          }
          return item;
        });
      }

      if (!newKeys.length || newKeys.indexOf(key) === -1) {
        newTag.push({
          key: key,
          expire: expire === 0 ? 0 : this.time() + expire,
        });
      }

      this.cacheSetHandler(this.cacheExpire, newTag);
    }
  }

  /**
   * 缓存是否过期,过期自动删除
   * @param key 缓存键
   * @param $bool true = 删除,false = 不删除
   */
  private getExpireCahe(key: string, $bool?: boolean): boolean {
    try {
      let tag: CacheTag[] | any = this.cacheGetHandler(this.cacheExpire);
      let time = 0;
      let index: number | false = false;

      if (Array.isArray(tag)) {
        tag.forEach((item: CacheTag, i: number) => {
          if (item.key === key) {
            time = item.expire;
            index = i;
          }
        });

        if (time) {
          let newTime = parseInt(time.toString());
          if (time && time < this.time() && !Number.isNaN(newTime)) {
            if ($bool === undefined || $bool === true) {
              this.cacheClearHandler(key);
              if (index !== false) {
                tag.splice(index, 1);
                this.cacheSetHandler(this.cacheExpire, tag);
              }
            }
            return false;
          } else {
            return true;
          }
        } else {
          return !!this.cacheGetHandler(key);
        }
      }
      return false;
    } catch (e) {
      return false;
    }
  }

  /**
   * 设置缓存
   * @param key 缓存键
   * @param data 缓存数据
   * @param expire 过期时间（秒）
   */
  set(key: string, data: any, expire?: number): boolean {
    if (data === undefined) {
      return true;
    }

    if (typeof data === "object") {
      data = JSON.stringify(data);
    }

    try {
      this.setExpireCaheTag(key, expire);
      this.cacheSetHandler(key, data);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * 检测缓存是否存在
   * @param key 缓存键
   * @param isDel 是否删除过期缓存
   */
  has(key: string, isDel?: boolean): boolean {
    this.clearOverdue();
    return this.getExpireCahe(key, isDel);
  }

  /**
   * 获取缓存
   * @param key 缓存键
   * @param $default 默认值
   * @param expire 过期时间（秒）
   */
  get<T>(key: string, $default?: T | (() => T), expire?: number): any {
    this.clearOverdue();
    try {
      let isBe = this.getExpireCahe(key);
      let data = this.cacheGetHandler(key);

      if (data && isBe) {
        if (typeof $default === "boolean") {
          return JSON.parse(data);
        } else {
          return data;
        }
      } else {
        if (typeof $default === "function") {
          let value = ($default as () => T)();
          this.set(key, value, expire);
          return value;
        } else {
          this.set(key, $default, expire);
          return $default;
        }
      }
    } catch (e) {
      return null;
    }
  }

  /**
   * 删除缓存
   * @param key 缓存键
   */
  clear(key: string): boolean {
    try {
      let cahceValue: CacheTag[] | any = this.cacheGetHandler(this.cacheExpire);
      let index: number | false = false;

      if (cahceValue && Array.isArray(cahceValue)) {
        cahceValue.forEach((item: CacheTag, i: number) => {
          if (item.key === key) {
            index = i;
          }
        });

        if (index !== false) {
          cahceValue.splice(index, 1);
        }

        this.cacheSetHandler(this.cacheExpire, cahceValue);
      }

      this.cacheClearHandler(key);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * 清除过期缓存
   */
  private clearOverdue(): void {
    let cahceValue: CacheTag[] | any = this.cacheGetHandler(this.cacheExpire);
    let time = this.time();
    let newBeOverdueValue: string[] = [];
    let newTagValue: CacheTag[] = [];

    if (cahceValue && Array.isArray(cahceValue)) {
      cahceValue.forEach((item: CacheTag) => {
        if (item) {
          if (
            (item.expire !== undefined && item.expire > time) ||
            item.expire === 0
          ) {
            newTagValue.push(item);
          } else {
            newBeOverdueValue.push(item.key);
          }
        }
      });
    }

    //保存没有过期的缓存标签
    if (newTagValue.length !== cahceValue.length) {
      this.cacheSetHandler(this.cacheExpire, newTagValue);
    }

    //删除过期缓存
    newBeOverdueValue.forEach((k) => {
      this.cacheClearHandler(k);
    });
  }
}

export default new Cache();
